package cn.lingyangwl.agile.gateway;

import cn.lingyangwl.agile.gateway.exception.AccessDeniedException;
import cn.lingyangwl.agile.gateway.exception.InvalidBearerTokenException;
import cn.lingyangwl.agile.model.enums.AuthErrorEnum;
import cn.lingyangwl.framework.core.response.Resp;
import cn.lingyangwl.framework.tool.core.exception.BaseException;
import cn.lingyangwl.agile.common.core.exception.enums.GlobalErrorEnum;
import cn.lingyangwl.agile.common.core.utils.WebFluxUtils;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.web.reactive.error.ErrorWebExceptionHandler;
import org.springframework.cloud.gateway.support.NotFoundException;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
import org.springframework.security.oauth2.core.OAuth2Error;
import org.springframework.web.server.ResponseStatusException;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

/**
 * 网关统一异常处理
 *
 * @author shenguangyang
 */
@Order(-1)
@Configuration
public class GatewayExceptionHandler implements ErrorWebExceptionHandler {
    private static final Logger log = LoggerFactory.getLogger(GatewayExceptionHandler.class);

    @Override
    public @NotNull Mono<Void> handle(ServerWebExchange exchange, @NotNull Throwable ex) {
        ServerHttpResponse response = exchange.getResponse();
        if (exchange.getResponse().isCommitted()) {
            return Mono.error(ex);
        }

        Resp<String> result = Resp.fail();
        result.setMsg(GlobalErrorEnum.FAIL.getMessage());
        HttpStatus status = HttpStatus.BAD_REQUEST;
        if (ex instanceof NotFoundException) {
            result.setMsg(GlobalErrorEnum.SERVICE_OFFLINE.getMessage());
            status = GlobalErrorEnum.SERVICE_OFFLINE.getStatus();
        } else if (ex instanceof ResponseStatusException) {
            ResponseStatusException responseStatusException = (ResponseStatusException) ex;
            result.setMsg(responseStatusException.getMessage());
        } else if (ex instanceof NullPointerException) {
            ex.printStackTrace();
        } else if (ex instanceof InvalidBearerTokenException) { // 针对令牌过期
            status = HttpStatus.UNAUTHORIZED;
            result.codeAndMsg(AuthErrorEnum.TOKEN_EXPIRED);
        } else if (ex instanceof OAuth2AuthenticationException) {
            OAuth2AuthenticationException authException = (OAuth2AuthenticationException) ex;
            OAuth2Error error = authException.getError();
            status = HttpStatus.UNAUTHORIZED;
            result.msg(error.getDescription());
        } else if (ex instanceof AccessDeniedException) {
            status = HttpStatus.FORBIDDEN;
            result.msg(GlobalErrorEnum.ACCESS_DENIED.getMessage());
        } else if (ex instanceof BaseException){
            result.setMsg(ex.getMessage());
        }
        if (log.isDebugEnabled()) {
            log.error("[网关异常处理]请求路径:{},异常信息: ", exchange.getRequest().getPath(), ex);
        } else {
            log.error("[网关异常处理]请求路径:{},异常信息: {}", exchange.getRequest().getPath(), ex.getMessage());
        }

        return WebFluxUtils.writeFail(exchange, status, result.getMsg());
    }
}